# -----------------------------------------------------------------------------
# Copyright (c) 2025, Southeast University (China)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#  - Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  - Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#  - Neither the name of the copyright holders nor the names of its
#    contributors may be used to endorse or promote products derived from
#    this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Jiajie Xu, Yanfang Zhang, Jiaqi Gao, Leyun Tian
# -----------------------------------------------------------------------------


###########################################
## Report annotated data for icexplorer
###########################################
set ::_inter_tcl [info script ]
if { [regexp {^\/} $::_inter_tcl] != 1 } {
  set cur_dir [pwd]
  set ::_inter_tcl ${cur_dir}/$::_inter_tcl
}


###############################################
# parameters
###############################################
set ::dumpVoltageData false
set ::ReportConstraintMaxCapacitance true
set ::skipCaseValuePins false
set ::deltaDelayThreshold 0.002
set ::removeFakeClockPins true
set ::skipNoise true
set ::iceCutnum 100000
set ::ignorePorts ""
set ::pathGroups ""
set ::skipILM false
set ::byFlattenPinTiming true
set ::dumpClockMethod 0
set ::use_new_index_collection 0
###############################################
# Internal parameters
###############################################
set ::_logFile "/dev/null"
set ::_internalPathPins ""
set ::_internalPathNets ""
set ::_drcTranFile ""
set ::_drcTranPins ""
set ::_tran_sigma 3
set ::_tran_clock_sigma "disabled"
set ::_skipModules ""
set ::_dumpNoise false
set ::_dumpToggleRate false
set ::_dumpDrcTranForAll false

##- check if command exists.
proc check_command { cmd } {
  set status [catch {$cmd -help > /dev/null}]
  return $status
}

##- check if gzip exists or not
proc no_gzip {} {
    set nogzip [catch {exec gzip -L}]
    return $nogzip
}

proc _log_begin_time {begin_time} {
  upvar 1 $begin_time int_btime
  set int_btime [clock milliseconds]
}

proc _get_elapsed_time {begin_time {update_begin_time true} } {
  upvar 1 $begin_time int_btime
  set int_etime [clock milliseconds]
  set result [expr {0.001 * ($int_etime - $int_btime)}]
  if {$update_begin_time} {
    set int_btime [clock milliseconds]
  }
  return $result
}


proc report_scenario_data_for_icexplorer { args } {
  parse_proc_arguments -args $args results
  if { [info exists results(-only_hier_path)] && [info exists results(-skip_modules)] } {
    puts stderr "Error: -only_hier_path and -skip_modules are mutually exclusive"
    return -1
  }
  set scenario_name $results(-scenario_name)
  if { ! [info exists results(-dir)] } {
    set dir .
  } else {
    set dir $results(-dir)
  }
  if { [info exists results(-dumpVoltageData)] } {
    set ::dumpVoltageData true
  } else {
    set ::dumpVoltageData false
  }
  if { [info exists results(-dump_toggle_rate)] } {
    set ::_dumpToggleRate true
  } else {
    set ::_dumpToggleRate false
  }
  # if dont specify -dumpNoise, honor $::skipNoise
  if { [info exists results(-dumpNoise)] } {
    set ::_dumpNoise true
  } else {
    set ::_dumpNoise false
  }
  if { [info exists results(-skip_modules)] } {
    set ::_internalPathPins ""
    set ::_internalPathNets ""
    set ::_skipModules ""
    foreach module $results(-skip_modules) {
      lappend ::_skipModules $module
      get_internal_objects $module true ::_internalPathPins ::_internalPathNets
    }
    puts "[sizeof_collection $::_internalPathPins] internal pins were skipped"
    puts "[sizeof_collection $::_internalPathNets] internal nets were skipped"
  }
  if { ! [info exists results(-only_hier_path)] } {
    set results(-only_hier_path) "."
  }
  set only_hier_path $results(-only_hier_path)
  regsub {\/$} $only_hier_path {} only_hier_path

  set ::_drcTranFile ""
  set ::_drcTranPins ""
  set ::_dumpDrcTranForAll false
  if { [info exists results(-drc_tran_for_all)] } {
    if { ! $::byFlattenPinTiming} {
      puts "Error: -drc_tran_for_all is unavailable when variable ::byFlattenPinTiming is false"
      return
    }
    set ::_dumpDrcTranForAll true
  }

  if { [info exists results(-drc_tran)] } {
    if { [catch {get_app_var timing_pocvm_max_transition_sigma}] || [catch {get_app_var timing_pocvm_max_transition_clock_sigma}]} {
      puts "Error: -drc_tran is unavailable under current version"
      return
    } 
    if { ! $::byFlattenPinTiming} {
      puts "Error: -drc_tran is unavailable when variable ::byFlattenPinTiming is false"
      return
    }
    set ::_drcTranFile $results(-drc_tran)
  }

  if { [info exists results(-tran_sigma)] } {
    set ::_tran_sigma $results(-tran_sigma)
  } else {
    set ::_tran_sigma [get_app_var timing_pocvm_max_transition_sigma]
  }

  if { [info exists results(-tran_clock_sigma)] } {
    set ::_tran_clock_sigma $results(-tran_clock_sigma)
  } else {
    set ::_tran_clock_sigma [get_app_var timing_pocvm_max_transition_clock_sigma]
  }

  if { [ info exists results(-parallel) ] } {
    report_annotated_data_for_icexplorer_in_parallel $scenario_name $dir $only_hier_path
  } else {
    report_annotated_data_for_icexplorer $scenario_name $dir $only_hier_path
  }
}

proc report_pba_data_for_icexplorer { args } {
  parse_proc_arguments -args $args results
  if {! [ info exists results(-dir)] } {
    set results(-dir) "."
  }
  if {! [info exists results(-delay_type)]} {
    set results(-delay_type) "min_max"
  }
  if {! [info exists results(-max_paths)]} {
    set results(-max_paths) 100000
  }
  if {! [info exists results(-nworst)]} {
    set results(-nworst) 100
  }
  if {! [info exists results(-setup_threshold)]} {
    set results(-setup_threshold) 0.0
  }
  if {! [info exists results(-hold_threshold)]} {
    set results(-hold_threshold) 0.0
  }
  if {! [info exists results(-pba_mode)]} {
    set results(-pba_mode) "path"
  }
  if {! [info exists results(-path_type)]} {
    set results(-path_type) "full_clock"
  }
  if {! [info exists results(-group)]} {
    set results(-group) ""
  }
  report_pba_paths_for_icexplorer $results(-scenario_name) $results(-dir) $results(-delay_type) $results(-max_paths) $results(-nworst) \
                                  $results(-setup_threshold) $results(-hold_threshold) $results(-pba_mode) $results(-group) $results(-path_type) 
}

proc report_endpoint_pba_data_for_icexplorer { args } {
  parse_proc_arguments -args $args results
  if {! [ info exists results(-dir)] } {
    set results(-dir) "."
  }
  if {! [info exists results(-pba_mode)]} {
    set results(-pba_mode) "path"
  }
  report_pba_path_endpoints_for_icexplorer $results(-scenario_name) $results(-dir) $results(-pba_mode) 
}

define_proc_attributes report_pba_data_for_icexplorer -info "Write PBA data file from PrimeTime for ICE2" \
   -define_args { \
     {-scenario_name "Specify scenario name" scenario string required} 
     {-dir "Directory under which PBA file will be created" dir string optional} 
     {-delay_type "Type of path delay, by default is min_max" type one_of_string {optional value_help {values {min max min_max}}} }
     {-max_paths "Maximum path number of per group, by default is 100000" max_paths int optional }
     {-nworst "Top N worst paths to one endpoint, by default is 100" nworst int optional}
     {-setup_threshold "Output paths with setup slack lesser than this value,by default is 0.0" setup_threshold float optional }
     {-hold_threshold "Output paths with hold slack lesser than this value, by default is 0.0" hold_threshold float optional}
     {-pba_mode "Path-based analysis mode,by default is path" effort one_of_string {optional value_help {values {path exhaustive none}} }}
     {-path_type "Specify the format ot timing report, by default is full_clock." path_type one_of_string \
                 {optional value_help {values {full full_clock full_clock_expanded}}} }
     {-group "Limit report to paths in these groups" group_name string optional}
   }
define_proc_attributes report_endpoint_pba_data_for_icexplorer -info "Write endpoint PBA data file from PrimeTime for ICE2, this is only used for refining gba timing" \
   -define_args { \
     {-scenario_name "Specify scenario name" scenario string required} 
     {-dir "Directory under which endpoint PBA file will be created" dir string optional} 
     {-pba_mode "Path-based analysis mode,by default is path" effort one_of_string {optional value_help {values {path exhaustive}} }}
   }
define_proc_attributes report_scenario_data_for_icexplorer -info "Write timing data files from PrimeTime for ICE2" \
   -define_args { \
   {-scenario_name "Specify scenario name" scenario string required} 
   {-dir "Directory under which the timing data files will be generated" dir string optional} 
   {-only_hier_path "Generate sub block timing data of current design, then use it on sub block ECO flow" hier_path string optional} 
   {-skip_modules "Internal timing data under specific modules will be skipped"  module_list list optional} 
   {-parallel "Generate all timing data files in parallel" "" boolean optional}
   {-dumpVoltageData  "Generate voltage rail file" "" boolean optional}
   {-dumpNoise "Generate si noise file" "" boolean optional} 
   {-dump_toggle_rate "Generate toggle rate file of nets" "" boolean optional}
   {-drc_tran "Specify the file which indicating the hierarchical paths using uncoupled drc tran by scenario, it's mutually exclusive with -drc_tran_for_all" file_name string optional}
   {-drc_tran_for_all "Indicate the whole design using uncoupled drc tran, it's mutually exclusive with -drc_tran" "" boolean optional}
   {-tran_sigma "Specify the max transition sigma when using drc tran, by default follows the setting in STA tool" tran_sigma float optional}
   {-tran_clock_sigma "Specify a larger max transition clock sigma than tran_sigma when using drc tran, by default follows the setting in STA tool" tran_clock_sigma float optional}
   } \
   -define_arg_groups { \
   {exclusive {-drc_tran -drc_tran_for_all}}
   }




######################################################################
# Procedure utilities
######################################################################
##-- report PBA paths for icexplorer
proc report_pba_paths_for_icexplorer {sce_name dir_name delay_type max_paths nworst setup_threshold hold_threshold pba_mode group_name {path_type full_clock} } {
  if {$delay_type != "min" && $delay_type != "max" && $delay_type != "min_max"} {
    puts stderr "delay_type only can be min, max or min_max"   
    return
  }
  if {$pba_mode != "path" && $pba_mode != "exhaustive" && $pba_mode != "none"} {
    puts stderr "pba_mode only can be path, exhaustive or none"   
    return
  }

  if {$dir_name == ""} {
    set dir_name "."
   } else {
    catch {exec mkdir -p $dir_name}
   }

  set file_name ${dir_name}/$sce_name\_data_timing_rpt.txt.gz
  #set timing_remove_clock_reconvergence_pessimism true
  #set pba_aocvm_only_mode false
  #set timing_aocvm_enable_analysis true
  set options "get_timing_paths -pba_mode $pba_mode -max_paths $max_paths -nworst $nworst -path_type full_clock_expanded "
  if { $group_name != ""} {
    set options "$options -group \"$group_name\" "
  }

  # test timing_report_include_eco_attributes and turn off it before report_timing
  set _turn_on_rpt_eco 0
  redirect -variable _app_var {report_app_var}
  if {[string match "*timing_report_include_eco_attributes*" $_app_var] == 1 } {
    if {[get_app_var timing_report_include_eco_attributes]} {
      set _turn_on_rpt_eco 1
      set_app_var timing_report_include_eco_attributes false
    }
  }
  unset -nocomplain _app_var

  # test timing_report_fixed_width_columns_on_left and turn off it before report_timing
  set _xtop_timing_report_flag 0
  if { ![catch {get_app_var timing_report_fixed_width_columns_on_left > /dev/null}] } {
     if { [get_app_var timing_report_fixed_width_columns_on_left] } {
        set_app_var timing_report_fixed_width_columns_on_left 0
        set _xtop_timing_report_flag 1
     }
  }

  _log_begin_time begin_time
  redirect -compress $file_name {
    puts [_generate_header "timing_report"]
    if {$delay_type == "min"} {
      set path_collection [eval "$options -slack_lesser_than $hold_threshold -delay_type min"]
      if {[sizeof_collection $path_collection] != 0} {
        report_timing $path_collection  -sig 4 -input_pins -cap -trans -derate -nosplit -path_type $path_type -crosstalk_delta
      }
      unset -nocomplain path_collection
    } elseif {$delay_type == "max"} {
      set path_collection [eval "$options -slack_lesser_than $setup_threshold -delay_type max"]
      if {[sizeof_collection $path_collection] != 0} {
        report_timing  $path_collection -sig 4 -input_pins -cap -trans -derate -nosplit -path_type $path_type -crosstalk_delta
      }
      unset -nocomplain path_collection
    } else {          
      set hold_path_collection [eval "$options -delay_type min -slack_lesser_than $hold_threshold "]
      if {[sizeof_collection $hold_path_collection] != 0} {
        report_timing  $hold_path_collection  -sig 4 -input_pins -cap -trans -derate -nosplit -path_type $path_type -crosstalk_delta
      }
      unset -nocomplain hold_path_collection
      set setup_path_collection [eval "$options -delay_type max -slack_lesser_than $setup_threshold"] 
      if {[sizeof_collection $setup_path_collection] != 0} {
        report_timing  $setup_path_collection -sig 4 -input_pins -cap -trans -derate -nosplit -path_type $path_type -crosstalk_delta
      }
      unset -nocomplain setup_path_collection
    }
  }
  set wall_time [_get_elapsed_time begin_time]
  # turn on timing_report_include_eco_attributes if it's ture before report_timing
  if {$_turn_on_rpt_eco} {
    set_app_var timing_report_include_eco_attributes true
  }
  unset -nocomplain _turn_on_rpt_eco
 
  # revert timing_report_fixed_width_columns_on_left 
  if { $_xtop_timing_report_flag } {
    set_app_var timing_report_fixed_width_columns_on_left 1
  }
  unset -nocomplain _xtop_timing_report_flag

  set ::_logFile "dump_${sce_name}_data.log"
  if { ![file writable .] } {
    set ::_logFile "/dev/null"
  }
  redirect -append $::_logFile {
    puts "Dump path time for $sce_name use time $wall_time"
  }
}

##-- report path endpoints for icexplorer
proc report_pba_path_endpoints_for_icexplorer {sce_name dir_name pba_mode } {
  set nworst 1
  set threshold 1000000
  set maxpath 2000000
  if {$pba_mode != "path" && $pba_mode != "exhaustive" && $pba_mode != "none"} {
    puts stderr "pba_mode only can be path, exhaustive or none"   
    return
  }

  if {$dir_name == ""} {
    set dir_name "."
   } else {
    catch {exec mkdir -p $dir_name}
   }

  set file_name ${dir_name}/$sce_name\_data_endpoint_pba_slack.txt.gz

  _log_begin_time begin_time
  redirect -compress $file_name {
    puts [_generate_header "endpoint_pba_slack"]
    set endpoint_collection_all [get_pins -quiet -filter "is_data_pin == true && (max_slack != INFINITY || min_slack != INFINITY)" -hierarchical]
    append_to_collection endpoint_collection_all [get_ports -quiet -filter "(direction == out || direction == inout) && (max_slack != INFINITY || min_slack != INFINITY)"]

    set obj_num [sizeof_collection $endpoint_collection_all]
    set iternum [expr $obj_num/$maxpath]
    for {set x 0} {$x <= $iternum} {incr x} {
       if {$obj_num == 0 } {
          break
       }
       if {$::use_new_index_collection != 0} {
         if {$x == $iternum} {
            set endpoint_collection [index_collection $endpoint_collection_all [expr $x * $maxpath] [expr $obj_num - 1]]
         } else {
            set endpoint_collection [index_collection $endpoint_collection_all [expr $x * $maxpath] [expr (($x+1) * $maxpath) - 1]]
         }
       } else {
         set endpoint_collection ""
         set count 0
         if {$x == $iternum} {
           set endpoint_collection [copy_collection $endpoint_collection_all]
         } else {
            foreach_in_collection endpoint $endpoint_collection_all {
              append_to_collection -append endpoint_collection $endpoint
              incr count    
              if {$count == $maxpath} {
                set endpoint_collection_all [remove_from_collection $endpoint_collection_all $endpoint_collection]
                break
              }
            }
         }
       }

      set options "report_timing -sig 4 -pba_mode $pba_mode -max_paths $maxpath -nworst $nworst -slack_lesser_than $threshold -nosplit -path_type end -to $endpoint_collection "
      if {[sizeof_collection $endpoint_collection] != 0} {
        redirect -variable tmp_array(0) " $options -delay_type max_rise "
        redirect -variable tmp_array(1) " $options -delay_type max_fall "
        redirect -variable tmp_array(2) " $options -delay_type min_rise "
        redirect -variable tmp_array(3) " $options -delay_type min_fall "
        set endpoint_name_flag 0
        set endpoint_num 0
        array set value_0 {}
        array set value_1 {}
        array set value_2 {}
        array set value_3 {}
        for {set index 0} {$index < [array size tmp_array]} {incr index} {
          set tmp $tmp_array($index)
          set data [split $tmp "\n"]
          set match 0
          set count 0
          foreach line $data {
            if {[llength $line] == 1} {
              if {[string match "*--------*" $line]} {
                set match 1
                continue
              }
            }
            if {$match == 0} {
              continue
            }
            if {[llength $line] == 7} {
              set value_array "value_$index"
              set pin_name [lindex $line 0]
              set ${value_array}($pin_name) [lindex $line 6]
              if { $endpoint_name_flag == 0 } {
                incr endpoint_num 1
              }
              incr count 1
            }
          }
          set endpoint_name_flag 1
        }
        #print endpoint slack
        puts [format "%12s%12s%12s%12s %s" "Max_Rise" "Max_Fall" "Min_Rise" "Min_Fall" "Point"]
        puts "--------------------------------------------------------------------------------"
        foreach_in_collection pin $endpoint_collection {
          set index [get_attribute $pin full_name]
          if { [info exists value_0($index)] == 0 } {
            set value_0($index) "*"
          }
          if { [info exists value_1($index)] == 0 } {
            set value_1($index) "*"
          }
          if { [info exists value_2($index)] == 0 } {
            set value_2($index) "*"
          }
          if { [info exists value_3($index)] == 0 } {
            set value_3($index) "*"
          }
          puts [format "%12s%12s%12s%12s %s" $value_0($index) $value_1($index) $value_2($index) $value_3($index) $index]
        }
      }
      unset -nocomplain  endpoint_collection
      unset -nocomplain  tmp_array
      unset -nocomplain  value_0
      unset -nocomplain  value_1
      unset -nocomplain  value_2
      unset -nocomplain  value_3
    }

    unset -nocomplain endpoint_collection_all
  }

  set wall_time [_get_elapsed_time begin_time]
  set ::_logFile "dump_${sce_name}_data.log"
  if { ![file writable .] } {
    set ::_logFile "/dev/null"
  }
  redirect -append $::_logFile {
    puts "Dump path endpoint slack time for $sce_name use time $wall_time"
  }
}

##-- Check if data number is mismatch with pin number
proc _number_mismatch_check {var1 num1 var2 num2 file_name} {
   if {$num1 != $num2} {
      redirect -append $::_logFile { puts "Error: $var1 number $num1 and $var2 number $num2 are mismatched when dumping $file_name" }
      puts stderr "Error: $var1 number $num1 and $var2 number $num2 are mismatched when dumping $file_name"
      return -1
   }
}

##-- Report design info to log
proc _output_design_info_to_log {log_file} {
   redirect $log_file {
      puts "##############################################################"
      puts "#Script Invoked: $::_inter_tcl"
      puts "#Design Name   : [get_attribute [current_design] full_name]"
      puts "#Cells  Number : [sizeof_collection [get_cells -quiet -hier * -filter "is_hierarchical == false"] ]"
      puts "#Nets   Number : [sizeof_collection [get_nets -quiet -hier * -top -filter "defined(total_capacitance_max)"] ]"
      puts "#Pins   Number : [sizeof_collection [get_pins -quiet -hier * -filter "is_hierarchical == false"] ]"
      puts "##############################################################"
   }
}

##-- Get drc tran pins under hier path
proc _get_drc_tran_pins {dtFile sce} {
   _log_begin_time begin_time_a
   set ::_drcTranPins ""
   if { $::_dumpDrcTranForAll } {
     set ::_drcTranPins [get_pins -hierarchical -quiet -filter "is_hierarchical == false && \
                                                                defined(drc_actual_max_transition)"]
   } else {
     set fid ""
     if { [catch {set fid [open $dtFile r]} err_msg] } {
        puts stderr "Error: $err_msg"
        error "$err_msg"
     }  
     set hier_paths ""
     set skip_paths ""
     set skip_flag 0
     while {![eof $fid]} {
        gets $fid line
        string trim $line
        if {[regexp {^\s*#} $line]} {
           continue 
        } elseif {[regexp {^\s*$} $line]} {
           continue
        } elseif {[regexp {^\s*\*\s*(\S+)} $line tmp sce_name]} {
           if {![regexp "^$sce_name" $sce]} { 
              set skip_flag 1
           } else {
              set skip_flag 0
           }  
        } elseif {!$skip_flag} {
           if { [regexp {^\[lminus\s+(\S+)\s+(\S.*)\]$} $line tmp top_path sub_paths] } {
              set hier_paths [concat $hier_paths $top_path]
              set skip_paths [concat $skip_paths $sub_paths]
           } else {
              set hier_paths [concat $hier_paths $line]
           }
        }  
     }  
     close $fid
     foreach hp $hier_paths {
        if {$hp != "/"} {
           append_to_collection -unique ::_drcTranPins [get_pins -hierarchical -quiet -filter "is_hierarchical == false && \
                                                                                            full_name=~$hp* && \
                                                                                            defined(drc_actual_max_transition)"]
        } else {
           append_to_collection -unique ::_drcTranPins [get_pins -hierarchical -quiet -filter "is_hierarchical == false && \
                                                                                            defined(drc_actual_max_transition)"]
        }
     }
     foreach sp $skip_paths {
        set ::_drcTranPins [remove_from_collection $::_drcTranPins [get_pins -hierarchical -quiet -filter "is_hierarchical == false && \
                                                                                            full_name=~$sp*"] ]
     }
   }
   set wall_time [_get_elapsed_time begin_time_a]
   redirect -append $::_logFile {puts [format "Get drc tran pins use real time %.3f seconds" $wall_time]}
}

##-- Get internal pins and nets under sub module
proc get_internal_objects {sub_module_name exclude_clock internal_pins internal_nets} {
   upvar 1 $internal_pins int_pins
   upvar 1 $internal_nets int_nets

   set cells [get_cells -quiet -hier * -filter "is_hierarchical == true && (ref_name == $sub_module_name || full_name == $sub_module_name)"]
   if {[sizeof_collection $cells] == 0} {
      return
   }

   foreach_in_collection itr $cells {
      current_instance [get_object_name $itr]
      set all_pins [get_pins -quiet -hier *]
      set all_nets [get_nets -quiet -hier * -top]
      current_instance
      if {[sizeof_collection $all_pins] == 0} {
         continue
      }

      set in_ports [get_pins -quiet -of_objects $itr -filter "direction == in  || direction == inout"]
      if {$exclude_clock} {
         set in_ports [get_pins -quiet -of_objects $itr -filter "(direction == in  || direction == inout) && is_clock_pin == false"]
      }
      set fanout_pins ""
      if {[sizeof_collection $in_ports] > 0} {
         set fanout_pins [all_fanout -from $in_ports  -flat -trace_arcs all]
         set tmp_pins [all_fanin -pin_levels 3 -flat -to $fanout_pins -trace_arcs all]
         append_to_collection -unique fanout_pins $tmp_pins
      }

      set out_ports [get_pins -quiet -of_objects $itr -filter "direction == out || direction == inout"]
      if {$exclude_clock} {
         set out_ports [get_pins -quiet -of_objects $itr -filter "(direction == out  || direction == inout) && is_clock_pin == false"]
      }
      set fanin_pins ""
      if {[sizeof_collection $out_ports] > 0} {
         set fanin_pins  [all_fanin  -to $out_ports -flat -trace_arcs all]
         set tmp_pins [all_fanout -pin_levels 2 -flat -from $fanin_pins -trace_arcs all]
         append_to_collection -unique fanin_pins $tmp_pins
      }

      set io_pins $fanin_pins
      append_to_collection -unique io_pins $fanout_pins

      set tmp_pins [remove_from_collection $all_pins $io_pins]
      append_to_collection -unique int_pins $tmp_pins

      set io_nets [get_nets -top -quiet -of_objects $io_pins]
      set tmp_nets [remove_from_collection $all_nets $io_nets]
      append_to_collection -unique int_nets $tmp_nets
   }
}

##-- filter out internal pins
proc _eraseInternalPins {pins} {
  upvar 1 $pins org_pins
  if {[sizeof_collection $org_pins] == 0} {
    return
  }
  if {[sizeof_collection $::_internalPathPins] > 0} {
    set org_pins [remove_from_collection $org_pins $::_internalPathPins]
  }
}

##-- filter out internal nets
proc _eraseInternalNets {nets} {
  upvar 1 $nets org_nets
  if {[sizeof_collection $org_nets] == 0} {
    return
  }
  if {[sizeof_collection $::_internalPathNets] > 0} {
    set org_nets [remove_from_collection $org_nets $::_internalPathNets]
  }
}

##-- Get file handler
proc _get_fp {file_name} {
   set fid ""
   if {[no_gzip] == 0} {
      if { [catch {open "| gzip -1 > $file_name.gz" w} fid] } {
         puts stderr "Failed to open file: $file_name.gz"
         error "Failed to open file: $file_name.gz"
      }
   } else {
      if { [catch {open $file_name w} fid] } {
         puts stderr "Failed to open file: $file_name"
         error "Failed to open file: $file_name"
      }
   }
   return $fid
}

##-- Output header information.
proc _generate_header {type {version 3.0}} {
   set header "****************************************\n"
   append header "Design   : [get_attribute [current_design] full_name]\n"
   append header "Report   : $type \n"
   append header "Vendor   : PT\n"
   append header "Version  : $version\n"
   append header "TimeUnit : [get_pt_unit time]\n"
   append header "CapUnit  : [get_pt_unit cap]\n"
   append header "ResUnit  : [get_pt_unit res]\n"
   append header "Current_instance : [current_instance .]\n"
   append header "****************************************\n"
   return $header
}

##-- Generate the finish file after get all data from PT
proc _generate_finish_file {file_name} {
   if {[sizeof_collection [current_design] ] == 0} {
      return
   }

   set fid ""
   if { [catch {open $file_name w} fid] } {
      puts stderr "Failed to open file: $file_name"
      error "Failed to open file: $file_name"
   }
   puts $fid "Vendor   : PT"
   puts $fid "Version  : 3.0"
   close $fid
}


##-- Get maximum val of two variables.
proc max_value {var1 var2} {
   if {$var1 > $var2} {
      return $var1
   } else {
      return $var2
   }
}

##-- Get minimum val of two variables.
proc min_value {var1 var2} {
   if {$var1 < $var2 && $var1 != ""} {
      return $var1
   } else {
      return $var2
   }
}

##-- Exclude delta slew when report_constraint -max_transition etc.
proc _is_exclude_delta_slew {  } {
   if {[catch {set a $::si_xtalk_max_transition_mode}] == 0} {
      if {$::si_xtalk_max_transition_mode == "reliability"} {
         return false
      } else {
         return true
      }
   }
   if {[catch {set a $::timing_si_exclude_delta_slew_for_transition_constraint}] == 0} {
      return $::timing_si_exclude_delta_slew_for_transition_constraint
   }
   return true
}

proc write_collection_directly { obj_class obj_col obj_num attr_name map_format file_name fid } {
   set tmp [get_attribute -quiet -value_list $obj_col $attr_name]
   set attr_num [llength $tmp]
   set tmp [string map $map_format $tmp]
   puts $fid $tmp
   unset -nocomplain tmp

   if {$obj_num != $attr_num} {
      redirect -append $::_logFile { puts "Error: $obj_class number $obj_num and its $attr_name attribute number $attr_name are mismatched when dumping $file_name" }
      puts stderr "Error: $obj_class number $obj_num and its $attr_name attribute number $attr_name are mismatched when dumping $file_name"
      return -1
   }
}

proc write_collection_by_split { obj_class obj_col obj_num attr_name map_format file_name fid } {
   if {$obj_num == 0} {
     return
   }
   set attr_num 0
   if {$::use_new_index_collection != 0} {
     set iternum [expr $obj_num/$::iceCutnum]
     for {set x 0} {$x <= $iternum} {incr x} {
        if {$obj_num == 0 } {
           break
        }
        if {$x == $iternum} {
           set obj_tmp [index_collection $obj_col [expr $x * $::iceCutnum] [expr $obj_num - 1]]
        } else {
           set obj_tmp [index_collection $obj_col [expr $x * $::iceCutnum] [expr (($x+1) * $::iceCutnum) - 1]]
        }
        set tmp [get_attribute -quiet -value_list $obj_tmp $attr_name]
        set attr_num [expr $attr_num + [llength $tmp]]
        set tmp [string map $map_format $tmp]
        puts $fid $tmp
     }
     unset -nocomplain tmp
     unset -nocomplain obj_tmp
   } else {
     set datas [get_attribute -quiet -value_list $obj_col $attr_name]
     set attr_num [llength $datas]
     set iternum [expr $attr_num/$::iceCutnum]
     for {set x 0} {$x <= $iternum} {incr x} {
        set tmp [lrange $datas [expr $x * $::iceCutnum] [expr (($x+1) * $::iceCutnum) - 1]]
        set tmp [string map $map_format $tmp]
        puts $fid $tmp
     }
     unset -nocomplain tmp
     unset -nocomplain datas
   }

   if {$obj_num != $attr_num} {
      redirect -append $::_logFile { puts "Error: $obj_class number $obj_num and its $attr_name attribute number $attr_name are mismatched when dumping $file_name" }
      puts stderr "Error: $obj_class number $obj_num and its $attr_name attribute number $attr_name are mismatched when dumping $file_name"
      return -1
   }
}

##-- get pin timing data
proc report_pin_timing_for_icexplorer {file_name} {
   set fid [_get_fp $file_name]
   redirect -append $::_logFile { puts "Before report_pin_timing mem is [mem] , cputime is [cputime %g]" }
   ## Output header.
   puts -nonewline $fid [_generate_header "fast_report_pin_timing"]
   puts $fid "#si_enable_analysis $::si_enable_analysis"
   puts $fid "#timing_si_exclude_delta_slew_for_transition_constraint [_is_exclude_delta_slew]"
   catch {puts $fid "#timing_enable_slew_variation [get_app_var timing_enable_slew_variation]"}
   puts $fid ""

   ## for designs
   puts $fid "\n#Design  design_name  max_transition  max_capacitance"
   set designs [get_designs *]
   foreach_in_collection dd $designs {
      puts -nonewline $fid [format "%s" [get_attribute $dd full_name] ]
      set maxtrans [get_attribute -quiet $dd max_transition]
      if {$maxtrans == ""} {
         puts -nonewline $fid "\t*" 
      } else {
         puts -nonewline $fid [format "\t%.4f" $maxtrans]
      }
      set maxcaps [get_attribute -quiet $dd max_capacitance]
      if {$maxcaps == ""} {
         puts $fid "\t*" 
      } else {
         puts $fid [format "\t%.4f" $maxcaps]
      }
   }
   unset -nocomplain designs

   ## Output max transition of pin.
   redirect -append $::_logFile { puts "Before report max_trans mem is [mem] , cputime is [cputime %g]" }
   set pins [get_pins -hier * -filter "is_hierarchical == false && defined(max_transition)"]
   _eraseInternalPins pins
   set number [sizeof_collection $pins]
   puts $fid "\n#MaxTransition pins max_transition $number"
   puts $fid "#pins_name $number"
   write_collection_by_split "MaxTransition pins" $pins $number "full_name" {" " "\n" "{" "" "}" ""} $file_name $fid
   redirect -append $::_logFile { puts "After  report max_trans name mem is [mem] , cputime is [cputime %g]" }

   set iternum [expr $number/$::iceCutnum]
   set datasNum_eq_pinNum 1
   ## judge if all pins constraining_max_transition exist, if so, use constraining_max_transition, otherwise use max_transition
   if {$::use_new_index_collection != 0} { 
     for {set x 0} {$x <= $iternum} {incr x} {
        if {$number == 0 } {
           break
        }
        if {$x == $iternum} {
          set pins_tmp [index_collection $pins [expr $x * $::iceCutnum] [expr $number - 1]]
        } else {
          set pins_tmp [index_collection $pins [expr $x * $::iceCutnum] [expr (($x+1) * $::iceCutnum) - 1]]
        }
        set datasNum [llength [get_attribute -quiet -value_list $pins_tmp constraining_max_transition]]
        if {$datasNum != [sizeof_collection $pins_tmp] } {
          set datasNum_eq_pinNum 0
          break
        }
     }
   } else {
     set datasNum [llength [get_attribute -quiet -value_list $pins constraining_max_transition]]
     if { $datasNum != $number } {
       set datasNum_eq_pinNum 0
     }
   }

   puts $fid "#max_transition $number"
   if { $datasNum_eq_pinNum == 1 } {
      write_collection_by_split "MaxTransition pins" $pins $number "constraining_max_transition" {" " "\n"} $file_name $fid
   } else {
      write_collection_by_split "MaxTransition pins" $pins $number "max_transition" {" " "\n"} $file_name $fid
   }
   redirect -append $::_logFile { puts "After  report max_trans data mem is [mem] , cputime is [cputime %g]" }

   ## Output port timing.
   report_ports_timing_for_icexplorer $fid
   redirect -append $::_logFile { puts "After  report ports data mem is [mem] , cputime is [cputime %g]" }

   ## Output transition.
   set pins ""
   if {$::skipCaseValuePins} {
      set pins [get_pins -quiet -hier * -filter "is_hierarchical == false && \
                                         defined(actual_rise_transition_max) && \
                                         defined(actual_fall_transition_max) && \
                                         defined(actual_rise_transition_min) && \
                                         defined(actual_fall_transition_min) && \
                                         (undefined(case_value) || \
                                         (defined(case_value) && case_value != 0 && case_value != 1))"]
   } else {
      set pins [get_pins -quiet -hier * -filter "is_hierarchical == false && \
                                         defined(actual_rise_transition_max) && \
                                         defined(actual_fall_transition_max) && \
                                         defined(actual_rise_transition_min) && \
                                         defined(actual_fall_transition_min)"]
   }

   _eraseInternalPins pins

   ## separate drc tran pins
   set drc_pins [remove_from_collection -intersect $::_drcTranPins $pins]
   if {[sizeof_collection $drc_pins] == 0} {
      redirect -append $::_logFile { puts "Before report slack_trans data mem is [mem] , cputime is [cputime %g]" }
      set number [sizeof_collection $pins]
      puts $fid "\n#PinTransition $number"
      puts $fid "#pins_name $number"
      write_collection_by_split "PinTransition pins" $pins $number "full_name" {" " "\n" "{" "" "}" ""} $file_name $fid
      redirect -append $::_logFile { puts "After  report slack_trans name mem is [mem] , cputime is [cputime %g]" }

      puts $fid "#actual_rise_transition_max $number"
      write_collection_by_split "PinTransition pins" $pins $number "actual_rise_transition_max" {" " "\n"} $file_name $fid
      redirect -append $::_logFile { puts "After  report setup_rise_trans mem is [mem] , cputime is [cputime %g]" }

      puts $fid "#actual_fall_transition_max $number"
      write_collection_by_split "PinTransition pins" $pins $number "actual_fall_transition_max" {" " "\n"} $file_name $fid
      redirect -append $::_logFile { puts "After  report setup_fall_trans mem is [mem] , cputime is [cputime %g]" }

      puts $fid "#actual_rise_transition_min $number"
      write_collection_by_split "PinTransition pins" $pins $number "actual_rise_transition_min" {" " "\n"} $file_name $fid
      redirect -append $::_logFile { puts "After  report hold_rise_trans mem is [mem] , cputime is [cputime %g]" }

      puts $fid "#actual_fall_transition_min $number"
      write_collection_by_split "PinTransition pins" $pins $number "actual_fall_transition_min" {" " "\n"} $file_name $fid
      redirect -append $::_logFile { puts "After  report hold_fall_trans mem is [mem] , cputime is [cputime %g]" }


      ## Output delta transition.
      if {$::si_enable_analysis && [_is_exclude_delta_slew] == false} {
         puts $fid "#annotated_rise_transition_delta_max $number"
         write_collection_by_split "PinTransition pins" $pins $number "annotated_rise_transition_delta_max" {" " "\n"} $file_name $fid
         redirect -append $::_logFile { puts "After  report max_rise_delta_trans data mem is [mem] , cputime is [cputime %g]" }

         puts $fid "#annotated_fall_transition_delta_max $number"
         write_collection_by_split "PinTransition pins" $pins $number "annotated_fall_transition_delta_max" {" " "\n"} $file_name $fid
         redirect -append $::_logFile { puts "After  report max_fall_delta_trans data mem is [mem] , cputime is [cputime %g]" }

         puts $fid "#annotated_rise_transition_delta_min $number"
         write_collection_by_split "PinTransition pins" $pins $number "annotated_rise_transition_delta_min" {" " "\n"} $file_name $fid
         redirect -append $::_logFile { puts "After  report min_rise_delta_trans data mem is [mem] , cputime is [cputime %g]" }
         
         puts $fid "#annotated_fall_transition_delta_min $number"
         write_collection_by_split "PinTransition pins" $pins $number "annotated_fall_transition_delta_min" {" " "\n"} $file_name $fid
         redirect -append $::_logFile { puts "After  report min_fall_delta_trans data mem is [mem] , cputime is [cputime %g]" }
      }
   } else {
      ## set timing_pocvm_max_transition_sigma for drc_actual_max_transition dumping
      set tranSigma_ori $::_tran_sigma
      if { [get_app_var timing_pocvm_max_transition_sigma] != $::_tran_sigma } {
         set tranSigma_ori [get_app_var timing_pocvm_max_transition_sigma]
         set_app_var timing_pocvm_max_transition_sigma $::_tran_sigma
      }
      ## set timing_pocvm_max_transition_clock_sigma for drc_actual_max_transition dumping
      set tranClockSigma_ori $::_tran_clock_sigma
      if { [get_app_var timing_pocvm_max_transition_clock_sigma] != $::_tran_clock_sigma } {
         set tranClockSigma_ori [get_app_var timing_pocvm_max_transition_clock_sigma]
         set_app_var timing_pocvm_max_transition_clock_sigma $::_tran_clock_sigma
      }
  
      ## set si_xtalk_max_transition_mode as uncoupled for drc_actual_max_transition dumping
      set si_tran_mode_ori "uncoupled"
      if { ![catch {get_app_var si_xtalk_max_transition_mode}] } {
         if { ![string equal [get_app_var si_xtalk_max_transition_mode] "uncoupled"] } {
            set si_tran_mode_ori [get_app_var si_xtalk_max_transition_mode]
            set_app_var si_xtalk_max_transition_mode "uncoupled"
         }
      }

      set rest_pins [remove_from_collection $pins $drc_pins]

      redirect -append $::_logFile { puts "Before report slack_trans data mem is [mem] , cputime is [cputime %g]" }
      set number_rest_pins [sizeof_collection $rest_pins]
      set number_drc_pins [sizeof_collection $drc_pins]
      set number [expr $number_rest_pins + $number_drc_pins]
      puts $fid "\n#PinTransition $number"
      puts $fid "#pins_name $number"
      write_collection_by_split "PinTransition pins" $rest_pins $number_rest_pins "full_name" {" " "\n" "{" "" "}" ""} $file_name $fid
      write_collection_by_split "PinTransition pins" $drc_pins $number_drc_pins "full_name" {" " "\n" "{" "" "}" ""} $file_name $fid
      redirect -append $::_logFile { puts "After  report slack_trans name mem is [mem] , cputime is [cputime %g]" }

      puts $fid "#actual_rise_transition_max $number"
      write_collection_by_split "PinTransition pins" $rest_pins $number_rest_pins "actual_rise_transition_max" {" " "\n"} $file_name $fid
      write_collection_by_split "PinTransition pins" $drc_pins $number_drc_pins "drc_actual_max_transition" {" " "\n"} $file_name $fid
      redirect -append $::_logFile { puts "After  report setup_rise_trans mem is [mem] , cputime is [cputime %g]" }

      puts $fid "#actual_fall_transition_max $number"
      write_collection_by_split "PinTransition pins" $rest_pins $number_rest_pins "actual_fall_transition_max" {" " "\n"} $file_name $fid
      write_collection_by_split "PinTransition pins" $drc_pins $number_drc_pins "drc_actual_max_transition" {" " "\n"} $file_name $fid
      redirect -append $::_logFile { puts "After  report setup_fall_trans mem is [mem] , cputime is [cputime %g]" }

      puts $fid "#actual_rise_transition_min $number"
      write_collection_by_split "PinTransition pins" $rest_pins $number_rest_pins "actual_rise_transition_min" {" " "\n"} $file_name $fid
      write_collection_by_split "PinTransition pins" $drc_pins $number_drc_pins "drc_actual_max_transition" {" " "\n"} $file_name $fid
      redirect -append $::_logFile { puts "After  report hold_rise_trans mem is [mem] , cputime is [cputime %g]" }

      puts $fid "#actual_fall_transition_min $number"
      write_collection_by_split "PinTransition pins" $rest_pins $number_rest_pins "actual_fall_transition_min" {" " "\n"} $file_name $fid
      write_collection_by_split "PinTransition pins" $drc_pins $number_drc_pins "drc_actual_max_transition" {" " "\n"} $file_name $fid
      redirect -append $::_logFile { puts "After  report hold_fall_trans mem is [mem] , cputime is [cputime %g]" }
      
      ## revert timing_pocvm_max_transition_sigma
      if { $tranSigma_ori != $::_tran_sigma } {
         set_app_var  timing_pocvm_max_transition_sigma $tranSigma_ori
      }
      unset -nocomplain tranSigma_ori

      ## revert timing_pocvm_max_transition_clock_sigma
      if { $tranClockSigma_ori != $::_tran_clock_sigma } {
         set_app_var  timing_pocvm_max_transition_clock_sigma $tranClockSigma_ori
      }
      unset -nocomplain tranClockSigma_ori
      
      ## revert si_xtalk_max_transition_mode
      if { ![string equal $si_tran_mode_ori "uncoupled"] } {
         set_app_var si_xtalk_max_transition_mode $si_tran_mode_ori
      }
      unset -nocomplain si_tran_mode_ori

      ## Output delta transition.
      if {$::si_enable_analysis && [_is_exclude_delta_slew] == false} {
         puts $fid "#annotated_rise_transition_delta_max $number"
         write_collection_by_split "PinTransition pins" $rest_pins $number_rest_pins "annotated_rise_transition_delta_max" {" " "\n"} $file_name $fid
         write_collection_by_split "PinTransition pins" $drc_pins $number_drc_pins "annotated_rise_transition_delta_max" {" " "\n"} $file_name $fid
         redirect -append $::_logFile { puts "After  report max_rise_delta_trans data mem is [mem] , cputime is [cputime %g]" }

         puts $fid "#annotated_fall_transition_delta_max $number"
         write_collection_by_split "PinTransition pins" $rest_pins $number_rest_pins "annotated_fall_transition_delta_max" {" " "\n"} $file_name $fid
         write_collection_by_split "PinTransition pins" $drc_pins $number_drc_pins "annotated_fall_transition_delta_max" {" " "\n"} $file_name $fid
         redirect -append $::_logFile { puts "After  report max_fall_delta_trans data mem is [mem] , cputime is [cputime %g]" }

         puts $fid "#annotated_rise_transition_delta_min $number"
         write_collection_by_split "PinTransition pins" $rest_pins $number_rest_pins "annotated_rise_transition_delta_min" {" " "\n"} $file_name $fid
         write_collection_by_split "PinTransition pins" $drc_pins $number_drc_pins "annotated_rise_transition_delta_min" {" " "\n"} $file_name $fid
         redirect -append $::_logFile { puts "After  report min_rise_delta_trans data mem is [mem] , cputime is [cputime %g]" }

         puts $fid "#annotated_fall_transition_delta_min $number"
         write_collection_by_split "PinTransition pins" $rest_pins $number_rest_pins "annotated_fall_transition_delta_min" {" " "\n"} $file_name $fid
         write_collection_by_split "PinTransition pins" $drc_pins $number_drc_pins "annotated_fall_transition_delta_min" {" " "\n"} $file_name $fid
         redirect -append $::_logFile { puts "After  report min_fall_delta_trans data mem is [mem] , cputime is [cputime %g]" }
      }
   }

   ## Output max_capacitance
   set pins [get_pins -quiet -hier * -filter "is_hierarchical == false && defined(max_capacitance)"]
   _eraseInternalPins pins
   set number [sizeof_collection $pins]
   puts $fid "\n#MaxCapacitance pins max_capacitance $number"
   puts $fid "#pins_name $number"
   write_collection_by_split "MaxCapacitance pins" $pins $number "full_name" {" " "\n" "{" "" "}" ""} $file_name $fid
   redirect -append $::_logFile { puts "After  report max_cap name mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#max_capacitance $number"
   write_collection_by_split "MaxCapacitance pins" $pins $number "max_capacitance" {" " "\n"} $file_name $fid
   redirect -append $::_logFile { puts "After  report max_cap data mem is [mem] , cputime is [cputime %g]" }
   unset -nocomplain pins

   if {$::ReportConstraintMaxCapacitance} {
     puts $fid "\n"
     puts $fid "#constraint_max_capacitance"
     redirect -variable constraint_max_cap_data {report_constraint -max_capacitance -all_violators -sig 5 -nosplit}
     puts $fid $constraint_max_cap_data
     redirect -append $::_logFile { puts "After  report constraint -max_capa mem is [mem] , cputime is [cputime %g]" }
   }

   close $fid
}


proc report_pin_timing { file_name } {
  set fid [_get_fp $file_name]
  redirect  -append $::_logFile { puts "Before report_pin_timing mem is [mem] , cputime is [cputime %g]" }
  ## Output header.
  puts -nonewline $fid [_generate_header "fast_report_pin_timing" 4.0]
  puts $fid "#si_enable_analysis $::si_enable_analysis"
  puts $fid "#timing_si_exclude_delta_slew_for_transition_constraint [_is_exclude_delta_slew]"
  catch {puts $fid "#timing_enable_slew_variation [get_app_var timing_enable_slew_variation]"}
  puts $fid ""

  ## for designs
  puts $fid "\n#Design  design_name  max_transition  max_capacitance"
  set designs [get_designs *]
  foreach_in_collection dd $designs {
    puts -nonewline $fid [format "%s" [get_attribute $dd full_name] ]
    set maxtrans [get_attribute -quiet $dd max_transition]
    if {$maxtrans == ""} {
      puts -nonewline $fid "\t*" 
    } else {
      puts -nonewline $fid [format "\t%.4f" $maxtrans]
    }
    set maxcaps [get_attribute -quiet $dd max_capacitance]
    if {$maxcaps == ""} {
      puts $fid "\t*" 
    } else {
      puts $fid [format "\t%.4f" $maxcaps]
    }
  }
  unset -nocomplain designs
  ## report ports timing
  report_ports_timing_for_icexplorer $fid
  _write_instance_pin_data [get_cells -quiet] $fid
  redirect -append $::_logFile { puts "After write pin constraints: mem is [mem] , cputime is [cputime %g]" }
  if {$::ReportConstraintMaxCapacitance} {
    puts $fid "\n"
    puts $fid "#constraint_max_capacitance"
    redirect -channel $fid {report_constraint -max_capacitance -all_violators -sig 5 -nosplit}
  }
  close $fid
}
proc _write_instance_pin_data {cells fid} {
  if {[sizeof_collection $cells] < 1} {
    return
  }
  set leaf_cells [filter_collection $cells "is_hierarchical == false"]
  _write_leaf_instances $leaf_cells $fid
  set hier_cells [filter_collection $cells "is_hierarchical == true && is_black_box == false"]
  foreach_in_collection cell  $hier_cells {
    set module_name [get_attribute $cell ref_name]
    set hier_name [get_attribute $cell full_name]
    if { [lsearch $::_skipModules $module_name] >= 0 ||
         [lsearch $::_skipModules $hier_name] >= 0} {
      continue
    }
    puts $fid "Hier $hier_name"
    current_instance $cell
    _write_instance_pin_data [get_cells -quiet] $fid
    puts $fid "End $hier_name"
    current_instance ..
  }
}
proc _write_leaf_instances {cells fid} {
  if {[sizeof_collection $cells] < 1} {
    return
  }
  set pins [get_pins -quiet -of_object $cells -filter "defined(max_transition)"]
  set count [sizeof_collection $pins]
  if {$count > 0} {
    puts $fid "#MaxTransition pins max_transition $count"
    set cell_base_name [get_attribute -value_list $pins cell.base_name]
    puts $fid "#Base_cell_name $count"
    puts $fid [join $cell_base_name "\n"]
    unset -nocomplain cell_base_name
    puts $fid "#Lib_pin_name $count"
    set pin_name [get_attribute -value_list $pins lib_pin_name]
    puts $fid [string map {" " "\n" "{" "" "}" ""} $pin_name]
    unset -nocomplain pin_name
    set datas [get_attribute -quiet -value_list $pins constraining_max_transition]
    if { [llength $datas] == [sizeof_collection $pins]} {
      puts $fid "#max_transition [llength $datas]"
      puts $fid [string map {" " "\n"} $datas]
      unset -nocomplain datas
    } else {
      unset -nocomplain datas
      set datas [get_attribute -value_list $pins max_transition]
      puts $fid "#max_transition [llength $datas]"
      puts $fid [string map {" " "\n"} $datas]
      unset -nocomplain datas
    }
  }
  set pins ""
  if {$::skipCaseValuePins} {
     set pins [get_pins -quiet -of_object $cells  \
                               -filter "defined(actual_rise_transition_max) && \
                                        defined(actual_fall_transition_max) && \
                                        defined(actual_rise_transition_min) && \
                                        defined(actual_fall_transition_min) && \
                                        (undefined(case_value) || \
                                        (defined(case_value) && case_value != 0 && case_value != 1))"]
  } else {
     set pins [get_pins -quiet -of_object $cells \
                               -filter "defined(actual_rise_transition_max) && \
                                        defined(actual_fall_transition_max) && \
                                        defined(actual_rise_transition_min) && \
                                        defined(actual_fall_transition_min)"]
  }
  set count [sizeof_collection $pins]
  if {$count > 0} {
    puts $fid "\n#PinTransition [sizeof_collection $pins]"
    set cell_base_name [get_attribute -value_list $pins cell.base_name]
    puts $fid "#Base_cell_name $count"
    puts $fid [join $cell_base_name "\n"]
    unset -nocomplain cell_base_name
    puts $fid "#Lib_pin_name $count"
    set pin_name [get_attribute -value_list $pins lib_pin_name]
    puts $fid [string map {" " "\n" "{" "" "}" ""} $pin_name]
    unset -nocomplain pin_name
    puts $fid "#actual_rise_transition_max $count"
    set datas [get_attribute -quiet -value_list $pins actual_rise_transition_max]
    puts $fid [string map {" " "\n"} $datas]
    unset -nocomplain datas
    puts $fid "#actual_fall_transition_max $count"
    set datas [get_attribute -quiet -value_list $pins actual_fall_transition_max]
    puts $fid [string map {" " "\n"} $datas]
    unset -nocomplain datas
    puts $fid "#actual_rise_transition_min $count"
    set datas [get_attribute -quiet -value_list $pins actual_rise_transition_min]
    puts $fid [string map {" " "\n"} $datas]
    unset -nocomplain datas
    puts $fid "#actual_fall_transition_min $count"
    set datas [get_attribute -quiet -value_list $pins actual_fall_transition_min]
    puts $fid [string map {" " "\n"} $datas]
    unset -nocomplain datas
  
    ## output delta transition
    if {$::si_enable_analysis && [_is_exclude_delta_slew] == false} {
      set pins_length [sizeof_collection $pins]
      set datas [get_attribute -quiet -value_list $pins annotated_rise_transition_delta_max]
      set data_length [llength $datas]
      if {[expr abs($pins_length - $data_length)] <= 1} {
        puts $fid "#annotated_rise_transition_delta_max [llength $datas]"
        puts $fid [string map {" " "\n"} $datas]
      }
      unset -nocomplain datas
      set datas [get_attribute -quiet -value_list $pins annotated_fall_transition_delta_max]
      set data_length [llength $datas]
      if {[expr abs($pins_length - $data_length)] <= 1} {
        puts $fid "#annotated_fall_transition_delta_max [llength $datas]"
        puts $fid [string map {" " "\n"} $datas]
      }
      unset -nocomplain datas
      set datas [get_attribute -quiet -value_list $pins annotated_rise_transition_delta_min]
      set data_length [llength $datas]
      if {[expr abs($pins_length - $data_length)] <= 1} {
        puts $fid "#annotated_rise_transition_delta_min [llength $datas]"
        puts $fid [string map {" " "\n"} $datas]
      }
      unset -nocomplain datas
      set datas [get_attribute -quiet -value_list $pins annotated_fall_transition_delta_min]
      set data_length [llength $datas]
      if {[expr abs($pins_length - $data_length)] <= 1} {
        puts $fid "#annotated_fall_transition_delta_min [llength $datas]"
        puts $fid [string map {" " "\n"} $datas]
      }
      unset -nocomplain datas
    }
  }
  ## Output max_capacitance
  set pins [get_pins -quiet -of_object $cells -filter "defined(max_capacitance)"]
  set count [sizeof_collection $pins]
  if {$count > 0} {
    puts $fid "\n#MaxCapacitance pins max_capacitance $count" 
    puts $fid "#Base_cell_name $count"
    set cell_base_name [get_attribute -value_list $pins cell.base_name]
    puts $fid [join $cell_base_name "\n"]
    unset -nocomplain cell_base_name
    puts $fid "#Lib_pin_name $count"
    set pin_name [get_attribute -value_list $pins lib_pin_name]
    puts $fid [string map {" " "\n" "{" "" "}" ""} $pin_name]
    unset -nocomplain pin_name
    set datas [get_attribute -quiet -value_list $pins max_capacitance]
    puts $fid "#max_capacitance $count"
    puts $fid [string map {" " "\n"} $datas]
    unset -nocomplain pins
  }
}

##-- get case value
proc report_case_value_for_icexplorer {file_name} {
   set fid [_get_fp $file_name]
   redirect -append $::_logFile { puts "Before report case_value data mem is [mem] , cputime is [cputime %g]" }
   ## Output header.
   puts $fid [_generate_header "report_case_value"]
   ## only dump case value when timing_enable_max_transition_set_case_analysis is off
   if { ! [get_app_var timing_enable_max_transition_set_case_analysis] } {
      ## case value 0
      puts $fid "\n#case_value_0_pins"
      ## for ports
      set ports [get_ports -filter "defined(case_value) && case_value == 0" -quiet]
      set datas [get_attribute -value_list $ports full_name]
      set number [llength $datas]
      if { $number > 0 } {
        set iternum [expr $number/$::iceCutnum]
        for {set x 0} {$x <= $iternum} {incr x} {
           set tmp [lrange $datas [expr $x * $::iceCutnum] [expr (($x+1) * $::iceCutnum) - 1]]
           puts $fid [join $tmp "\n"]
        }
      }
      unset datas
      ## for pins
      set pins [get_pins -hierarchical -filter "defined(case_value) && case_value == 0" -quiet]
      set datas [get_attribute -value_list $pins full_name]
      set number [llength $datas]
      if { $number > 0 } {
        set iternum [expr $number/$::iceCutnum]
        for {set x 0} {$x <= $iternum} {incr x} {
           set tmp [lrange $datas [expr $x * $::iceCutnum] [expr (($x+1) * $::iceCutnum) - 1]]
           puts $fid [join $tmp "\n"]
        }
      }
      unset datas
      
      ## case value 1
      puts $fid "\n#case_value_1_pins"
      ## for ports
      set ports [get_ports -filter "defined(case_value) && case_value == 1" -quiet]
      set datas [get_attribute -value_list $ports full_name]
      set number [llength $datas]
      if { $number > 0 } {
        set iternum [expr $number/$::iceCutnum]
        for {set x 0} {$x <= $iternum} {incr x} {
           set tmp [lrange $datas [expr $x * $::iceCutnum] [expr (($x+1) * $::iceCutnum) - 1]]
           puts $fid [join $tmp "\n"]
        }
      }
      unset datas
      ## for pins
      set pins [get_pins -hierarchical -filter "defined(case_value) && case_value == 1" -quiet]
      set datas [get_attribute -value_list $pins full_name]
      set number [llength $datas]
      if { $number > 0 } {
        set iternum [expr $number/$::iceCutnum]
        for {set x 0} {$x <= $iternum} {incr x} {
           set tmp [lrange $datas [expr $x * $::iceCutnum] [expr (($x+1) * $::iceCutnum) - 1]]
           puts $fid [join $tmp "\n"]
        }
      }
      unset datas
   }

   redirect -append $::_logFile { puts "After  report case_value mem is [mem] , cputime is [cputime %g]" }
   close $fid
}

##-- Report global slack
proc report_global_slack_for_icexplorer {file_name} {
   set fid [_get_fp $file_name]

   puts $fid [_generate_header "report_global_slack"]
   redirect -channel $fid {report_global_slack -sig 9 -nosplit}
 
   close $fid
}

proc report_total_capacitances_for_icexplorer {file_name} {
   set fid [_get_fp $file_name]
   redirect -append $::_logFile { puts "Before report net_cap data mem is [mem] , cputime is [cputime %g]" }

   ## Output header.
   puts $fid [_generate_header "fast_report_total_capacitance"]

   ## for ports
   puts $fid "\n#Port port_name pin_capacitance_max pin_capacitance_min"
   set ports [get_ports * -filter "defined(pin_capacitance_max) || defined(pin_capacitance_min)"]
   foreach_in_collection pp $ports {
      set cap_max [get_attribute -quiet $pp pin_capacitance_max]
      set cap_min [get_attribute -quiet $pp pin_capacitance_min]
      if {$cap_max == ""} { set cap_max $cap_min }
      if {$cap_min == ""} { set cap_min $cap_max }
      puts $fid [format "%s\t%.6f\t%.6f" \
                       [get_attribute $pp full_name] \
                       $cap_max \
                       $cap_min ]
   }
   unset -nocomplain ports

   ## for nets rc_annotated_segment == true 
   set nets [get_nets -quiet -hier * -top -filter " \
                                  defined(total_capacitance_max) && defined(total_capacitance_min) && \
                                  defined(wire_capacitance_max) && defined(wire_capacitance_min) && \
                                  defined(net_resistance_max) && defined(net_resistance_min)"]
   _eraseInternalNets nets

   set number [sizeof_collection $nets]
   puts $fid "\n#nets_name $number"
   write_collection_by_split "nets" $nets $number "full_name" {" " "\n" "{" "" "}" ""} $file_name $fid
   redirect -append $::_logFile { puts "After  report net_cap name mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#total_capacitance_max $number"
   write_collection_by_split "nets" $nets $number "total_capacitance_max" {" " "\n"} $file_name $fid
   redirect -append $::_logFile { puts "After  report total_cap_max mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#total_ccs_capacitance_max_rise $number"
   write_collection_by_split "nets" $nets $number "total_ccs_capacitance_max_rise" {" " "\n"} $file_name $fid
   redirect -append $::_logFile { puts "After  report total_ccs_capacitance_max_rise mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#total_ccs_capacitance_max_fall $number"
   write_collection_by_split "nets" $nets $number "total_ccs_capacitance_max_fall" {" " "\n"} $file_name $fid
   redirect -append $::_logFile { puts "After  report total_ccs_capacitance_max_fall mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#total_capacitance_min $number"
   write_collection_by_split "nets" $nets $number "total_capacitance_min" {" " "\n"} $file_name $fid
   redirect -append $::_logFile { puts "After  report total_cap_min mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#wire_capacitance_max $number"
   write_collection_by_split "nets" $nets $number "wire_capacitance_max" {" " "\n"} $file_name $fid
   redirect -append $::_logFile { puts "After  report wire_cap_max mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#wire_capacitance_min $number"
   write_collection_by_split "nets" $nets $number "wire_capacitance_min" {" " "\n"} $file_name $fid
   redirect -append $::_logFile { puts "After  report wire_cap_min mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#net_resistance_max $number"
   write_collection_by_split "nets" $nets $number "net_resistance_max" {" " "\n"} $file_name $fid
   redirect -append $::_logFile { puts "After  report net_res_max mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#net_resistance_min $number"
   write_collection_by_split "nets" $nets $number "net_resistance_min" {" " "\n"} $file_name $fid
   redirect -append $::_logFile { puts "After  report net_res_min mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#total_coupling_capacitance $number"
   write_collection_by_split "nets" $nets $number "total_coupling_capacitance" {" " "\n" "{}" "0.0"} $file_name $fid
   redirect -append $::_logFile { puts "After  report total_coupling_cap mem is [mem] , cputime is [cputime %g]" }
    
   unset -nocomplain nets

   close $fid
}

##-- report timing derate
proc report_timing_derate_for_icexplorer {file_name} {
   set fid [_get_fp $file_name]

   puts $fid [_generate_header "report_timing_derate"]
   redirect -channel $fid {report_timing_derate -nosplit -significant_digits 4}

   if {$::timing_aocvm_enable_analysis} {
     puts $fid "\n"
     puts $fid "#aocvm_guardband"
     redirect -channel $fid {report_timing_derate -aocvm_guardband -nosplit -significant_digits 4}
   }
   if {$::timing_pocvm_enable_analysis} {
     puts $fid "\n"
     puts $fid "#pocvm_guardband"
     redirect -channel $fid {report_timing_derate -pocvm_guardband -nosplit -significant_digits 4}
   }

   puts $fid "\n"
   puts $fid "#increment_derate"
   redirect -channel $fid {report_timing_derate -increment -nosplit -significant_digits 4}

   close $fid
}

##-- report dont touch objects
proc report_dont_touch_objects_for_icexplorer {file_name} {
   set fid [_get_fp $file_name]
   ## Ouput header.
   puts $fid [_generate_header "report_dont_touch_objects"]

   ## Type : Net or Cell
   puts $fid "Name    Type"
   puts $fid "--------------------------------------------------------------------------------"

   set cells [get_cells -quiet -hier * -filter "dont_touch == true"]
   foreach_in_collection pp $cells {
      puts $fid "[get_attribute $pp full_name] Cell"
   }
   unset -nocomplain cells

   set nets [get_nets -quiet -hier * -filter "dont_touch == true"]
   foreach_in_collection pp $nets {
      puts $fid "[get_attribute $pp full_name] Net"
   }
   unset -nocomplain nets

   close $fid    
}

######################################################
# report clock pins
######################################################
proc report_used_as_clock_pins_for_icexplorer {file_name} {
  set fid [_get_fp $file_name]
  ##Put header in it.
  puts $fid [_generate_header "report_used_as_clock_pins"]
  puts $fid "--------------------------------------------------------------------------------"

  if {[sizeof_collection [get_clocks -quiet *]] == 0} {
    close $fid
    return
  }
### dont use -include_clock_gating_network
### typical clock gating network is from Latch/Q to an input pin of AND(OR) cell, and this pin
### is enable pin. if user sets gating check constraint, then the paths in gating network are the
### real paths and should be fixed, so we can't include clock gating network
#    set pins [get_clock_network_objects -type pin -include_clock_gating_network]
  set pins [get_clock_network_objects -type pin ]
  if {[sizeof_collection $pins] == 0} {
    close $fid
    return
  }
    
  if { $::removeFakeClockPins } { 
    set pins [filter_collection $pins "is_clock_used_as_clock != false or is_clock_used_as_data != true" ]
  }
  _eraseInternalPins pins
  ## get clock pin names all at once, maybe crash if pin name is too long and pin number is too much
  if {$::dumpClockMethod == 1} {
    set datas [get_attribute -value_list $pins full_name]
    set total_number [llength $datas]
    set iternum [expr $total_number/$::iceCutnum]
    for {set x 0}  {$x <= $iternum}  {incr x} {
       set tmp [lrange $datas [expr $x * $::iceCutnum] [expr (($x + 1) * $::iceCutnum) - 1]]
       set tmp [string map {" " "\n" "{" "" "}" ""} $tmp]
       puts $fid $tmp
    }
    unset -nocomplain datas
    unset -nocomplain pins
  ## get clock pin names by segment, maybe crash at index_collection command
  } elseif {$::dumpClockMethod == 2} {
    set number [sizeof_collection $pins]
    set iternum [expr $number/$::iceCutnum]
    for {set x 0} {$x <= $iternum} {incr x} {
       if {$number == 0 } {
          break
       }
       if {$x == $iternum} {
         set pins_tmp [index_collection $pins [expr $x * $::iceCutnum] [expr $number - 1]]
       } else {
         set pins_tmp [index_collection $pins [expr $x * $::iceCutnum] [expr (($x+1) * $::iceCutnum) - 1]]
       }
       set tmp [get_attribute -quiet -value_list $pins_tmp full_name]
       set tmp [string map {" " "\n" "{" "" "}" ""} $tmp]
       puts $fid $tmp
       unset -nocomplain tmp
    }
    unset -nocomplain pins
  ## get clock pin names one by one, it's slowest but will not cause crash
  } else {
    set number 0
    set tmp ""
    foreach_in_collection pins_tmp $pins {
      incr number
      lappend tmp [get_attribute -quiet -value_list $pins_tmp full_name]
      if {$number == $::iceCutnum} {
        set tmp [string map {" " "\n" "{" "" "}" ""} $tmp]
        puts $fid $tmp

        set number 0
        set tmp ""
      }
    }
    if {$number != 0} {
      set tmp [string map {" " "\n" "{" "" "}" ""} $tmp]
      puts $fid $tmp
    }

    unset -nocomplain tmp
    unset -nocomplain pins
  }
    
  set clocks [get_clocks * -quiet -filter "is_generated == true"]
  if {[llength $clocks] > 0} {
    redirect -variable d {report_clock_timing -type latency -clock $clocks -ver -no}
    set data [split $d "\n"]
    set match 0
    foreach line $data {
      if {[llength $line] == 1} {
        if {[string match "*--------*" $line]} {
          set match 1
          continue
        }
      }
      if {[string match "*total clock latency*" $line]} {
        set match 0
        continue
      }
      if {$match == 0 || [llength $line] < 6} {
        continue
      }
      puts $fid [lindex $line 0]
    }
  }

  ## get clock sources
  set pins ""
  append_to_collection pins [get_attribute [get_clocks -quiet] sources -quiet] -unique
  set number [sizeof_collection $pins]
  puts $fid "\n#clock_root $number"
  write_collection_directly "Used as clock pins" $pins $number "full_name" {" " "\n" "{" "" "}" ""} $file_name $fid
  unset -nocomplain pins

  close $fid
}

##-- Report cell voltage.
proc report_rail_voltage_for_icexplorer {file_name} {
   if {!$::dumpVoltageData} {
      return
   }
   set fid [_get_fp $file_name]
   ## Output header.
   puts $fid [_generate_header "report_rail_voltage"]
   redirect -append $::_logFile { puts "Before report_rail_voltage mem is [mem] , cputime is [cputime %g]" }

   set pins [get_pins -quiet -hier * -filter "is_hierarchical == false && \
                                       direction == out && \
                                       defined(power_rail_voltage_max) && \
                                       defined(power_rail_voltage_min)"]
   _eraseInternalPins pins
   if {[sizeof_collection $pins] == 0} {
      return;
   }
    
   set number [sizeof_collection $pins]
   puts $fid "#name $number"
   write_collection_by_split "rail_voltage pins" $pins $number "full_name" {" " "\n" "{" "" "}" ""} $file_name $fid
   redirect -append $::_logFile { puts "After report_rail_voltage names mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#power_rail_voltage_max $number"
   write_collection_by_split "rail_voltage pins" $pins $number "power_rail_voltage_max" {" " "\n"} $file_name $fid
   redirect -append $::_logFile { puts "After report power_rail_voltage_max names mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#power_rail_voltage_min $number"
   write_collection_by_split "rail_voltage pins" $pins $number "power_rail_voltage_min" {" " "\n"} $file_name $fid
   redirect -append $::_logFile { puts "After report power_rail_voltage_min names mem is [mem] , cputime is [cputime %g]" }
   unset -nocomplain pins
   close $fid
}

##-- report si delta 
proc report_delta_data_for_icexplorer {file_name threshold} {
   set fid [_get_fp $file_name]
   ## Ouput header.
   puts $fid [_generate_header "fast_report_delta"]

   if {!$::si_enable_analysis} {
      close $fid
      return
   }
   redirect -append $::_logFile { puts "Before report delta data mem is [mem] , cputime is [cputime %g]" }

   set nets [get_nets -quiet -hier * -top_net_of_hierarchical_group]
   _eraseInternalNets nets
   set time_unit [get_pt_unit time]
   if { $time_unit == 1e-12 } {
     set threshold [expr $threshold * 1000]
   }
   set arcs [get_timing_arcs -quiet -of_objects $nets -filter "\
                       annotated_delay_delta_max_rise >= $threshold || annotated_delay_delta_max_rise <= -$threshold || \
                       annotated_delay_delta_max_fall >= $threshold || annotated_delay_delta_max_fall <= -$threshold || \
                       annotated_delay_delta_min_rise >= $threshold || annotated_delay_delta_min_rise <= -$threshold || \
                       annotated_delay_delta_min_fall >= $threshold || annotated_delay_delta_min_fall <= -$threshold"]
   set number [sizeof_collection $arcs]
   puts $fid "#Delta_delay $number"
   redirect -append $::_logFile { puts "After  get_timing_arcs mem is [mem] , cputime is [cputime %g]" }

   puts $fid "#annotated_delay_delta_max_rise $number"
   write_collection_by_split "#Delta_delay arcs" $arcs $number "annotated_delay_delta_max_rise" {" " "\n"} $file_name $fid

   puts $fid "#annotated_delay_delta_max_fall $number"
   write_collection_by_split "#Delta_delay arcs" $arcs $number "annotated_delay_delta_max_fall" {" " "\n"} $file_name $fid

   puts $fid "#annotated_delay_delta_min_rise $number"
   write_collection_by_split "#Delta_delay arcs" $arcs $number "annotated_delay_delta_min_rise" {" " "\n"} $file_name $fid

   puts $fid "#annotated_delay_delta_min_fall $number"
   write_collection_by_split "#Delta_delay arcs" $arcs $number "annotated_delay_delta_min_fall" {" " "\n"} $file_name $fid

   puts $fid "#from_pins_name [sizeof_collection $arcs]"
   foreach_in_collection arc $arcs {
      puts $fid [get_attribute [get_attribute $arc from_pin] full_name]
   }

   puts $fid "#to_pins_name [sizeof_collection $arcs]"
   foreach_in_collection arc $arcs {
      puts $fid [get_attribute [get_attribute $arc to_pin] full_name]
   }
   unset -nocomplain arcs

#   redirect -append $::_logFile { puts "Before get_pins for delta transition mem is [mem] , cputime is [cputime %g]" }
#
#   puts $fid ""
#   set pins [get_pins -quiet -hier * -filter "is_hierarchical == false && (\
#                      annotated_rise_transition_delta_max >= $threshold || annotated_rise_transition_delta_max <= -$threshold || \
#                      annotated_fall_transition_delta_max >= $threshold || annotated_fall_transition_delta_max <= -$threshold || \
#                      annotated_rise_transition_delta_min >= $threshold || annotated_rise_transition_delta_min <= -$threshold || \
#                      annotated_fall_transition_delta_min >= $threshold || annotated_fall_transition_delta_min <= -$threshold)"]
#   _eraseInternalPins pins
#   puts $fid "#Delta_transition [sizeof_collection $pins]"
#   redirect -append $::_logFile { puts "After  get_pins for delta transition mem is [mem] , cputime is [cputime %g]" }
#
#   set datas [get_attribute -value_list $pins annotated_rise_transition_delta_max]
#   puts $fid "#annotated_transition_delta_rise_max [llength $datas]"
#   set datas [string map {" " "\n"} $datas]
#   puts $fid $datas
#
#   set datas [get_attribute -value_list $pins annotated_fall_transition_delta_max]
#   puts $fid "#annotated_transition_delta_fall_max [llength $datas]"
#   set datas [string map {" " "\n"} $datas]
#   puts $fid $datas
#
#   set datas [get_attribute -value_list $pins annotated_rise_transition_delta_min]
#   puts $fid "#annotated_transition_delta_rise_min [llength $datas]"
#   set datas [string map {" " "\n"} $datas]
#   puts $fid $datas
#
#   set datas [get_attribute -value_list $pins annotated_fall_transition_delta_min]
#   puts $fid "#annotated_transition_delta_fall_min [llength $datas]"
#   set datas [string map {" " "\n"} $datas]
#   puts $fid $datas
#
#   set datas [get_attribute -value_list $pins full_name]
#   puts $fid "#to_pins_name [llength $datas]"
#   set number [llength $datas]
#   set iternum [expr $number/$::iceCutnum]
#   for {set x 0} {$x <= $iternum} {incr x} {
#      set tmp [lrange $datas [expr $x * $::iceCutnum] [expr (($x+1) * $::iceCutnum) - 1]]
#      set tmp [string map {" " "\n" "{" "" "}" ""} $tmp]
#      puts $fid $tmp
#   }
#   unset -nocomplain datas
#   unset -nocomplain pins
   redirect -append $::_logFile { puts "After  report delta datal mem is [mem] , cputime is [cputime %g]" }

   close $fid
}

##-- report si noise for icexplorer
proc report_si_noise_for_icexplorer {file_name} {
   set fid [_get_fp $file_name]
   if {!$::si_enable_analysis} {
      close $fid
      return
   }
   ## Output header.
   puts $fid [_generate_header "si_noise"]
   redirect -variable noiseParam {report_noise_parameters}
   set data [split $noiseParam "\n"]
   set match 0
   foreach line $data {
     if {[string match "*report_at_endpoint*" $line]} {
       set match 1
       continue
   }
   }
   if {$match == 1} {
     redirect -channel $fid {report_noise_violation_sources -nosplit -significant_digits 6 -verbose }
   } else {
     set_noise_parameters -analysis_mode report_at_endpoint
     redirect -channel $fid {report_noise_violation_sources -nosplit -significant_digits 6 -verbose }
     set_noise_parameters -analysis_mode report_at_source
   }

   close $fid
}

##-- Report io information.
proc report_ilm_objects_for_icexplorer {file_name } {
  set fid [_get_fp $file_name]
  redirect -append $::_logFile { puts "Before report_ilm_objects mem is [mem] , cputime is [cputime %g]" }
  ## Ouput header.
  puts $fid [_generate_header "report_ilm_objects"]
  if { $::skipILM } {
    puts $fid "\n#pins_name 0"
    close $fid
    return
  }
  set cur_inst [current_instance .]
  if { $cur_inst != "" } {
    close $fid
    return;
  }
  if { [llength $::ignorePorts] > 0 } {
    set ports_col [get_ports -quiet $::ignorePorts]
    if { [sizeof_collection $ports_col ] > 0 } {
      if { ![info exists ::hier_enable_analysis] && ![check_command identify_interface_logic] } {
        identify_interface_logic -ignorePorts [get_ports -quiet $::ignorePorts]
      } elseif { $::hier_enable_analysis == false && ![check_command identify_interface_logic]} {
        identify_interface_logic -ignorePorts [get_ports -quiet $::ignorePorts]
      } else {
        ## derive IO pins by fanin and fanout
        write_fanin_fanout_pins $fid $ports_col
        close $fid
        redirect -append $::_logFile { puts "After  report_ilm_objects mem is [mem] , cputime is [cputime %g]" }
        return;
      }
    } else {
      if { ![info exists ::hier_enable_analysis] && ![check_command identify_interface_logic]} {
        identify_interface_logic -auto_ignore
      } elseif { $::hier_enable_analysis == false && ![check_command identify_interface_logic]} {
        identify_interface_logic -auto_ignore
      } else {
        write_fanin_fanout_pins $fid
        close $fid
        redirect -append $::_logFile { puts "After  report_ilm_objects mem is [mem] , cputime is [cputime %g]" }
        return;
      }
    }
  } else {
    if { ![info exists ::hier_enable_analysis] && ![check_command identify_interface_logic] } {
      identify_interface_logic -auto_ignore
    } elseif { $::hier_enable_analysis == false && ![check_command identify_interface_logic]} {
      identify_interface_logic -auto_ignore
    } else {
      write_fanin_fanout_pins $fid
      close $fid
      redirect -append $::_logFile { puts "After  report_ilm_objects mem is [mem] , cputime is [cputime %g]" }
      return;
    }
  }

  ## get pins on io paths
  set ilm_pins [get_pins  -quiet -hierarchical * -filter "is_hierarchical == false && is_interface_logic_pin == true" ]

  set all_ports [get_ports *]
  if { [llength $::ignorePorts] > 0 } {
     set all_ports [remove_from_collection $all_ports [get_ports $::ignorePorts] ]
  }
  #append_to_collection -unique ilm_pins [get_ports *]
  set ilm_pins_name [get_attribute -quiet -value_list $ilm_pins full_name]
  set number [expr [llength $ilm_pins_name] + [sizeof_collection $all_ports]]
  puts $fid "\n#pins_name $number"
  set iternum [expr $number/$::iceCutnum]
  for {set x 0} {$x <= $iternum} {incr x} {
    set tmp [lrange $ilm_pins_name [expr $x * $::iceCutnum] [expr (($x+1) * $::iceCutnum) - 1]]
    set tmp [string map {" " "\n" "{" "" "}" ""} $tmp]
    puts $fid $tmp
  }
  foreach_in_collection pin_coll $all_ports {
    set dir [get_attribute [get_ports $pin_coll] direction]
    if { $dir == "input" || $dir == "in"} {
      set conn_net [get_nets -quiet -of_objects [get_port $pin_coll]]
      set ilm_flag false
      foreach_in_collection conn_pin [get_pins -leaf -of_objects [get_nets $conn_net]  -quiet \
                                  -filter "direction == in || direction == input || direction == inout" ] {
        set pin_interface [get_attribute [get_pins -quiet $conn_pin] is_interface_logic_pin]
	      if { $pin_interface } {
	        set ilm_flag true
            break
        }
      }
      if { $ilm_flag } {
        puts $fid [get_object_name $pin_coll]
      }
    } else {
      set conn_net [get_nets -quiet -of_objects [get_port $pin_coll]]
      set ilm_flag false
      foreach_in_collection conn_pin [get_pins -leaf -of_objects [get_nets $conn_net] -quiet \
                                   -filter "direction == out || direction == output || direction == inout" ] {
        set pin_interface [get_attribute [get_pins -quiet $conn_pin] is_interface_logic_pin]
	      if { $pin_interface } {
          set ilm_flag true
            break
        }
      }
      if { $ilm_flag } {
        puts $fid [get_object_name $pin_coll]
      }
    }
  }
  unset -nocomplain all_ports
  unset -nocomplain ilm_pins
  unset -nocomplain ilm_pins_name

  redirect -append $::_logFile { puts "After  report_ilm_objects mem is [mem] , cputime is [cputime %g]" }
  close $fid
}

##-- Report toggle rate of net.
proc report_toggle_rate_for_icexplorer {file_name } {
  set fid [_get_fp $file_name]
  redirect -append $::_logFile { puts "Before report toggle_rate mem is [mem] , cputime is [cputime %g]" }
  ## Ouput header.
  puts $fid [_generate_header "report_toggle_rate"]

  # test power_enable_analysis and turn on it if it's off
  set _xtop_power_enable_analysis_flag 0
  if { ![catch {get_app_var power_enable_analysis > /dev/null}] } {
     if { ! [get_app_var power_enable_analysis] } {
        set_app_var power_enable_analysis 1
        set _xtop_power_enable_analysis_flag 1
     }
  }

  # report toggle rate info
  set nets [get_nets -quiet -hierarchical -top_net_of_hierarchical_group]

  _eraseInternalNets nets
  
  set number [sizeof_collection $nets]
  puts $fid "\n#nets_name $number"
  write_collection_by_split "nets" $nets $number "full_name" {" " "\n" "{" "" "}" ""} $file_name $fid

  puts $fid "\n#toggle_rate $number"
  write_collection_by_split "nets" $nets $number "toggle_rate" {" " "\n" "{" "" "}" ""} $file_name $fid

  # revert power_enable_analysis
  if { $_xtop_power_enable_analysis_flag } {
    set_app_var power_enable_analysis false
  }
  unset -nocomplain _xtop_power_enable_analysis_flag


  redirect -append $::_logFile { puts "After  report toggle_rate mem is [mem] , cputime is [cputime %g]" }
  close $fid
}

##-- Get pt unit
proc get_pt_unit {type} {
   set timeunit 1e-9 
   set capunit  1e-12 
   set resunit  1000 
   set volunit  1
   redirect -variable units_data {report_units -nosplit }
   set lines [split $units_data "\n"]
   foreach {line} $lines {
      if {[llength $line] != 4} {
         continue
      }
      if {[lindex $line 0] == "Capacitive_load_unit"} {
         set capunit [lindex $line 2]
      }
      if {[lindex $line 0] == "Time_unit"} {
         set timeunit [lindex $line 2]
      }
      if {[lindex $line 0] == "Resistance_unit"} {
         set resunit [lindex $line 2]
      }
      if {[lindex $line 0] == "Voltage_unit"} {
         set volunit [lindex $line 2]
      }
   }

   if {$type == "time"} {
      return $timeunit
   } elseif {$type == "cap"} {
      return $capunit
   } elseif {$type == "vol"} {
      return $volunit
   } else {
      return $resunit
   }
}

##-- Check if need to update timing
proc check_pin_arrival_and_slack_time { log } {
  if {$::timing_save_pin_arrival_and_slack == false} {
    set inittime [cputime %g]
    puts "Now set timing_save_pin_arrival_and_slack true and do update_timing"
    set ::timing_save_pin_arrival_and_slack true
    update_timing
    set endtime [cputime %g]
    puts [format "update_timing use time %.4f" [expr $endtime - $inittime]]
    redirect -append $log {puts [format "update_timing use time %.4f" [expr $endtime - $inittime]] }
  }
}

##-- Check if need to update noise
proc check_si_enable_analysis { log } {
  if {$::si_enable_analysis == true} {
    set inittime [cputime %g]
    puts "Now do update_noise"
    update_noise
    set endtime [cputime %g]
    puts [format "update_noise use time %.4f" [expr $endtime - $inittime]]
    redirect -append $log {puts [format "update_noise use time %.4f" [expr $endtime - $inittime]] }
  }
}

##-- write timing data files in parallel
proc report_annotated_data_for_icexplorer_in_parallel { scenario_name dir_name {hier_path .} } {
  current_instance
  current_instance $hier_path
  catch { exec rm -rf ${dir_name}/${scenario_name}_data_finish }
  catch {exec mkdir -p $dir_name}
  set ::_logFile "dump_${scenario_name}_data.log"
  if {![file writable .]} {
    set ::_logFile "/dev/null"
  }
  _output_design_info_to_log $::_logFile
  check_pin_arrival_and_slack_time  $::_logFile

  if { $::_dumpNoise || ! $::skipNoise } {
    check_si_enable_analysis $::_logFile
  }

   _log_begin_time begin_time_total
   if { $::_drcTranFile != "" || $::_dumpDrcTranForAll } {
      _get_drc_tran_pins $::_drcTranFile $scenario_name
   }
   set nfile /dev/null
   set prefix_name "${dir_name}/${scenario_name}"

    #IO objects file
    _log_begin_time begin_time_a
    set fname ${prefix_name}_data_ilm_objects.txt
    redirect -file $nfile "report_ilm_objects_for_icexplorer $fname"
    set wall_time [_get_elapsed_time begin_time_a]
    redirect -append $::_logFile {puts [format "dump ilm objects use real time %.3f seconds" $wall_time]}

    parallel_execute -commands_only {
      {
        _log_begin_time begin_time_b
        set fname ${prefix_name}_data_pin_timing.txt
        if {$::byFlattenPinTiming} {
          redirect -file $nfile "report_pin_timing_for_icexplorer $fname"
        } else {
          redirect -file $nfile "report_pin_timing $fname"
        }
        if { [file exists $fname] } {
          catch { exec gzip -1 $fname }
        }
        set wall_time [_get_elapsed_time begin_time_b]
        redirect -append $::_logFile {puts [format "dump pin timing use real time %.3f seconds" $wall_time]}
      }
      { 
        _log_begin_time begin_time_b
        set fname ${prefix_name}_data_case_value.txt
        redirect -file $nfile "report_case_value_for_icexplorer $fname"
        if { [file exists $fname] } {
          catch { exec gzip -1 $fname }
        }
        set wall_time [_get_elapsed_time begin_time_b]
        redirect -append $::_logFile {puts [format "dump case value use real time %.3f seconds" $wall_time]}
      }
      { 
        _log_begin_time begin_time_b
        set fname ${prefix_name}_data_pin_slack.txt
        redirect -file $nfile "report_global_slack_for_icexplorer $fname"
        if { [file exists $fname] } {
          catch { exec gzip -1 $fname }
        }
        set wall_time [_get_elapsed_time begin_time_b]
        redirect -append $::_logFile {puts [format "dump global slack use real time %.3f seconds" $wall_time]}
      }
      {
        _log_begin_time begin_time_b
        set fname ${prefix_name}_data_total_capacitances.txt
        redirect -file $nfile "report_total_capacitances_for_icexplorer $fname"
        if { [file exists $fname] } {
          catch { exec gzip -1 $fname }
        }
        set wall_time [_get_elapsed_time begin_time_b]
        redirect -append $::_logFile {puts [format "dump total capacitances use real time %.3f seconds" $wall_time]}
      }
      {
        _log_begin_time begin_time_b
        set fname ${prefix_name}_data_timing_derates.txt
        redirect -file $nfile "report_timing_derate_for_icexplorer $fname"
        if { [file exists $fname] } {
          catch { exec gzip -1 $fname }
        }
        set wall_time [_get_elapsed_time begin_time_b]
        redirect -append $::_logFile {puts [format "dump derate use real time %.3f seconds" $wall_time]}
      }
      {
        _log_begin_time begin_time_b
        set fname ${prefix_name}_data_dont_touch_objects.txt
        redirect -file $nfile "report_dont_touch_objects_for_icexplorer $fname"
        if { [file exists $fname] } {
          catch { exec gzip -1 $fname }
        }
        set wall_time [_get_elapsed_time begin_time_b]
        redirect -append $::_logFile {puts [format "dump dont touch objects use real time %.3f seconds" $wall_time]}
      }
      {
        _log_begin_time begin_time_b
        set fname ${prefix_name}_data_used_as_clocks.txt
        redirect -file $nfile "report_used_as_clock_pins_for_icexplorer $fname"
        if { [file exists $fname] } {
          catch { exec gzip -1 $fname }
        }
        set wall_time [_get_elapsed_time begin_time_b]
        redirect -append $::_logFile {puts [format "dump clock pins use real time %.3f seconds" $wall_time]}
      }
      {
        _log_begin_time begin_time_b
        set fname ${prefix_name}_data_rail_voltage.txt
        redirect -file $nfile "report_rail_voltage_for_icexplorer $fname"
        if { [file exists $fname] } {
          catch { exec gzip -1 $fname }
        }
        set wall_time [_get_elapsed_time begin_time_b]
        redirect -append $::_logFile {puts [format "dump rail_voltage use real time %.3f second" $wall_time]}
      }
      {
        _log_begin_time begin_time_b
        set fname ${prefix_name}_data_si_delta.txt
        report_delta_data_for_icexplorer $fname $::deltaDelayThreshold
        if { [file exists $fname] } {
          catch { exec gzip -1 $fname }
        }
        set wall_time [_get_elapsed_time begin_time_b]
        redirect -append $::_logFile {puts [format "dump si delta use real time %.3f seconds" $wall_time]} 
      }
      {
        _log_begin_time begin_time_b
        if { $::_dumpNoise || ! $::skipNoise } {
          set fname ${prefix_name}_data_si_noise.txt
          redirect -file $nfile "report_si_noise_for_icexplorer $fname"
          if { [file exists $fname] } {
            catch { exec gzip -1 $fname }
          }
        }
        set wall_time [_get_elapsed_time begin_time_b]
        redirect -append $::_logFile {puts [format "dump si noise use real time %.3f seconds" $wall_time]} 
      }
     }

   set wall_time [_get_elapsed_time begin_time_total]
   redirect -append $::_logFile {puts [format "report annotatd data use real time %.3f seconds" $wall_time ]}
   _generate_finish_file ${dir_name}/${scenario_name}_data_finish
   current_instance
}

##-- write timing data files
proc report_annotated_data_for_icexplorer { scenario_name dir_name { hier_path . } } {
   current_instance
   current_instance $hier_path
   catch { exec rm -rf ${dir_name}/${scenario_name}_data_finish }
   if {$dir_name == ""} {
      set dir_name "."
   } else {
      catch {exec mkdir -p $dir_name}
   }
   set ::_logFile "dump_${scenario_name}_data.log"
   if { ![file writable .] } {
     set ::_logFile "/dev/null"
   }
   _output_design_info_to_log $::_logFile
   check_pin_arrival_and_slack_time  $::_logFile

   _log_begin_time begin_time
   if { $::_drcTranFile != "" || $::_dumpDrcTranForAll } {
      _get_drc_tran_pins $::_drcTranFile $scenario_name
   }
   set nfile /dev/null
   set prefix_name  "${dir_name}/${scenario_name}"
    _report_annotated_timing_data $prefix_name
   set wall_time [_get_elapsed_time begin_time]
   redirect -append $::_logFile {puts [format "report annotatd data use real time %.3f seconds" $wall_time ]}
   _generate_finish_file ${dir_name}/${scenario_name}_data_finish
   current_instance
}

##-- Write all timing data files
proc _report_annotated_timing_data {prefix_name} {
  # set null file 
  set nfile /dev/null
  _log_begin_time begin_time

  # pin timing.
  set fname ${prefix_name}_data_pin_timing.txt
  if {$::byFlattenPinTiming} {
    redirect -file $nfile "report_pin_timing_for_icexplorer $fname"
  } else {
    redirect -file $nfile "report_pin_timing $fname"
  }
  if { [file exists $fname] } {
    catch { exec gzip -1 $fname}
  }
  set wall_time [_get_elapsed_time begin_time]
  redirect -append $::_logFile {puts [format "dump pin timing use real time %.3f seconds" $wall_time]}
 
  # case value
  set fname ${prefix_name}_data_case_value.txt
  redirect -file $nfile "report_case_value_for_icexplorer $fname"
  if { [file exists $fname] } {
    catch { exec gzip -1 $fname}
  }
  set wall_time [_get_elapsed_time begin_time]
  redirect -append $::_logFile {puts [format "dump case value use real time %.3f seconds" $wall_time]}

  # global_slack.
  set fname ${prefix_name}_data_pin_slack.txt
  redirect -file $nfile "report_global_slack_for_icexplorer $fname"
  if { [file exists $fname] } {
    catch { exec gzip -1 $fname}
  }
  set wall_time [_get_elapsed_time begin_time]
  redirect -append $::_logFile {puts [format "dump global slack use real time %.3f seconds" $wall_time]}

  # wire(total) capacitances
  set fname ${prefix_name}_data_total_capacitances.txt
  redirect -file $nfile "report_total_capacitances_for_icexplorer $fname"
  if { [file exists $fname] } {
    catch { exec gzip -1 $fname}
  }
  set wall_time [_get_elapsed_time begin_time]
  redirect -append $::_logFile {puts [format "dump total capacitances use real time %.3f seconds" $wall_time]}

  # derate.
  set fname ${prefix_name}_data_timing_derates.txt
  redirect -file $nfile "report_timing_derate_for_icexplorer $fname"
  if { [file exists $fname] } {
    catch { exec gzip -1 $fname}
  }
  set wall_time [_get_elapsed_time begin_time]
  redirect -append $::_logFile {puts [format "dump derate use real time %.3f seconds" $wall_time]}

  # dont touch cells or nets.
  set fname ${prefix_name}_data_dont_touch_objects.txt
  redirect -file $nfile "report_dont_touch_objects_for_icexplorer $fname"
  if { [file exists $fname] } {
    catch { exec gzip -1 $fname}
  }
  set wall_time [_get_elapsed_time begin_time]
  redirect -append $::_logFile {puts [format "dump dont touch objects use real time %.3f seconds" $wall_time]}

  # used as clock pins
  set fname ${prefix_name}_data_used_as_clocks.txt
  redirect -file $nfile "report_used_as_clock_pins_for_icexplorer $fname"
  if { [file exists $fname] } {
    catch { exec gzip -1 $fname}
  }
  set wall_time [_get_elapsed_time begin_time]
  redirect -append $::_logFile {puts [format "dump clock pins use real time %.3f seconds" $wall_time]}

  # rail voltage
  set fname ${prefix_name}_data_rail_voltage.txt
  redirect -file $nfile "report_rail_voltage_for_icexplorer $fname"
  if { [file exists $fname] } {
    catch { exec gzip -1 $fname}
  }
  set wall_time [_get_elapsed_time begin_time]
  redirect -append $::_logFile {puts [format "dump rail_voltage use real time %.3f second" $wall_time]}

  # si delta
  set fname ${prefix_name}_data_si_delta.txt
  report_delta_data_for_icexplorer $fname $::deltaDelayThreshold
  if { [file exists $fname] } {
    catch { exec gzip -1 $fname}
  }
  set wall_time [_get_elapsed_time begin_time]
  redirect -append $::_logFile {puts [format "dump si delta use real time %.3f seconds" $wall_time]} 

  # si noise 
  if { $::_dumpNoise || ! $::skipNoise } {
    set fname ${prefix_name}_data_si_noise.txt
    redirect -file $nfile "report_si_noise_for_icexplorer $fname"
    if { [file exists $fname] } {
      catch { exec gzip -1 $fname}
    }
  }
  set wall_time [_get_elapsed_time begin_time]
  redirect -append $::_logFile {puts [format "dump si noise use real time %.3f seconds" $wall_time]} 

  #IO objects file
  set fname ${prefix_name}_data_ilm_objects.txt
  redirect -file $nfile "report_ilm_objects_for_icexplorer $fname"
  if { [file exists $fname] } {
    catch { exec gzip -1 $fname}
  }
  set wall_time [_get_elapsed_time begin_time]
  redirect -append $::_logFile {puts [format "dump ilm objects use real time %.3f seconds" $wall_time]}

  # toggle rate info
  if { $::_dumpToggleRate} {
    set fname ${prefix_name}_data_toggle_rate.txt
    redirect -file $nfile "report_toggle_rate_for_icexplorer $fname"
    if { [file exists $fname] } {
      catch { exec gzip -1 $fname}
    }
    set wall_time [_get_elapsed_time begin_time]
    redirect -append $::_logFile {puts [format "dump toggle rate use real time %.3f seconds" $wall_time]} 
  }

}

##-- Report port timing info.
proc report_ports_timing_for_icexplorer {fid} {
   puts $fid "\n#Port port_name Setup_RiseTrans Setup_FallTrans Hold_RiseTrans Hold_FallTrans Max_Trans  Max_Cap"
   set ports [get_ports *]
   foreach_in_collection pp $ports {
      # transition
      puts -nonewline $fid [get_attribute $pp full_name]
      puts -nonewline $fid "  [get_attribute -quiet $pp actual_rise_transition_max]"
      puts -nonewline $fid "  [get_attribute -quiet $pp actual_fall_transition_max]"
      puts -nonewline $fid "  [get_attribute -quiet $pp actual_rise_transition_min]"
      puts -nonewline $fid "  [get_attribute -quiet $pp actual_fall_transition_min]"

      ## max_transition
      set maxtransition [get_attribute -quiet $pp max_transition]
      if {$maxtransition == ""} {
         puts -nonewline $fid " \t*"
      } else {
         puts -nonewline $fid [format " \t%.6f" $maxtransition]
      }
      ## max_capacitance
      set maxcaps [get_attribute -quiet $pp max_capacitance]
      if {$maxcaps == ""} {
         puts -nonewline $fid " \t*"
      } else {
         puts -nonewline $fid [format " \t%.6f" $maxcaps]
      }

      puts $fid ""
   }
   unset -nocomplain ports
}

##############################################################################
### Write io pins by fanin and fanout.
##############################################################################
proc write_fanin_fanout_pins { fid {skip_ports ""} } {
  set all_ports [ remove_from_collection [get_ports *] $skip_ports]
  if { [sizeof_collection $all_ports] < 1 } {
    return;
  }
  set ilm_pins [all_fanout -quiet -from $all_ports -flat -trace_arcs all]
  append_to_collection -unique ilm_pins [all_fanin -to $all_ports \
                                         -flat -trace_arcs all]
  set ilm_pins_name [get_attribute -quiet -value_list $ilm_pins full_name]
  set number [sizeof_collection $ilm_pins]
  puts $fid "\n#pins_name $number";
  set iternum [expr $number/$::iceCutnum]
  for {set x 0} {$x <= $iternum} {incr x} {
    set tmp [lrange $ilm_pins_name [expr $x * $::iceCutnum] [expr (($x+1) * $::iceCutnum) - 1]]
    set tmp [string map {" " "\n" "{" "" "}" ""} $tmp]
    puts $fid $tmp
  }
}

##############################################################################
### Check if the index_collection support index2 or not
##############################################################################
proc check_index_collection_version {} {
  redirect -variable index_collection_help  "index_collection -help"
  return [string match "*index2*" $index_collection_help]
}

##############################################
proc ice_helps { } {
  puts ""
  puts "########################################################"
  puts "# This script is used for ICExplorer2                  #"
  puts "# Available commands:                                  #"
  puts "#  report_scenario_data_for_icexplorer                 #"
  puts "#  report_pba_data_for_icexplorer                      #"
  puts "#  report_endpoint_pba_data_for_icexplorer             #"
  puts "########################################################"
  help -verbose report_scenario_data_for_icexplorer
  help -verbose report_pba_data_for_icexplorer
  help -verbose report_endpoint_pba_data_for_icexplorer
}

set ::use_new_index_collection [check_index_collection_version]
ice_helps

